package com.ease.component.managers {

   import flash.display.DisplayObject;
   import flash.events.Event;
   import flash.events.EventDispatcher;
   import flash.utils.clearInterval;
   import flash.utils.setInterval;

   import mx.collections.ArrayCollection;
   import mx.core.Application;
   import mx.core.FlexGlobals;
   import mx.core.UIComponent;
   import mx.events.FlexEvent;
   import mx.logging.ILogger;

   public class ViewRefreshMonitor extends EventDispatcher {

      private var _view:DisplayObject = null;
      private var _refreshInterval:* = NaN;
      private var _taskIds:ArrayCollection = new ArrayCollection;
      private var _interval:Number = 10 * 1000;
      private var _allowMonitorOnInvisible:Boolean = false;

      public function ViewRefreshMonitor(view:DisplayObject, allowMonitorOnInvisible:Boolean = false):void {
         _view = view;
         _allowMonitorOnInvisible = allowMonitorOnInvisible;

         if (view != null) {
            view.addEventListener(Event.ADDED_TO_STAGE, onViewAdd);
            view.addEventListener(Event.REMOVED_FROM_STAGE, onViewRemove);
            addAppListenerToVisibleChanged();
         }
      }

      public function get interval():Number {
         return _interval;
      }

      public function set interval(value:Number):void {
         _interval = value;
      }

      private function addAppListenerToVisibleChanged():void {
         var app:Application = FlexGlobals.topLevelApplication as Application;

         // listen the event in its whole liftcycle.
         app.addEventListener(FlexEvent.SHOW, elementVisibleChanged, true);
         app.addEventListener(FlexEvent.HIDE, elementVisibleChanged, true);
         app.addEventListener(FlexEvent.SHOW, elementVisibleChanged);
         app.addEventListener(FlexEvent.HIDE, elementVisibleChanged);
      }

      private function removeAppListenerToVisibleChanged():void {
         var app:Application = FlexGlobals.topLevelApplication as Application;

         // remove listener.
         app.removeEventListener(FlexEvent.SHOW, elementVisibleChanged, true);
         app.removeEventListener(FlexEvent.HIDE, elementVisibleChanged, true);
         app.removeEventListener(FlexEvent.SHOW, elementVisibleChanged);
         app.removeEventListener(FlexEvent.HIDE, elementVisibleChanged);
      }

      private function elementVisibleChanged(event:FlexEvent):void {
         var container:UIComponent = event.target as UIComponent;

         if (container == null) {
            return;
         }

         var visible:Boolean = event.type == FlexEvent.SHOW;

         if (container.contains(_view) || container == _view) {
            if (visible && _view != container) {
               visible = viewChainVisible(_view.parent, container);

               if (visible && !_allowMonitorOnInvisible) {
                  visible = _view.visible;
               }
            }

            if (visible) {
               if (refreshCallback != null) {
                  refreshCallback();
               }
               start();
            } else {
               stop();
            }
         }
      }

      private function viewChainVisible(view:*, container:UIComponent):Boolean {
         var visible:Boolean = view.visible;

         if (view == container) {
            return visible;
         } else  {
            visible &&= viewChainVisible(view.parent, container);
         }

         return visible;
      }

      private function onViewRemove(event:Event):void {
         var view:DisplayObject = event.target as DisplayObject;

         if (view != null) {
            removeAppListenerToVisibleChanged();
         }

         if (view == _view) {
            stop();
         }
      }

      private function onViewAdd(event:Event):void {
         var view:DisplayObject = event.target as DisplayObject;

         if (view != null) {
            addAppListenerToVisibleChanged();
         }

         if (view == _view) {
            viewStability = false;
         }
      }

      private var _refreshCallback:Function = null;
      /**
       * Function to call in this refresher within the specified time interval.
       */
      public function get refreshCallback():Function {
         return _refreshCallback;
      }

      /**
       *  @private
       */
      public function set refreshCallback(value:Function):void {
         _refreshCallback = value;
      }

      private var _viewStability:Boolean = true;
      public function get viewStability():Boolean {
         return _viewStability;
      }

      /**
       *  @private
       */
      public function set viewStability(value:Boolean):void {
         _viewStability = value;

         if (!viewStability) {
            start();
         }
      }

      public function start():void {
         // Make sure the old one has been cleared
         stop();

         _refreshInterval = setInterval(intervalCallback, _interval);
      }

      private function intervalCallback():void {
         if (refreshCallback == null || viewStability == true ) {
            stop();
            return;
         }

         refreshCallback();
      }

      private function stop():void {
         if (!isNaN(_refreshInterval)) {
            clearInterval(_refreshInterval);
         }
      }
   }
}
